package co.yixiang.yshop.module.product.service.campaigninfo;

import cn.hutool.core.util.ObjectUtil;
import co.yixiang.yshop.framework.common.constant.ShopConstants;
import co.yixiang.yshop.framework.common.pojo.PageResult;
import co.yixiang.yshop.framework.common.util.date.DateUtils;
import co.yixiang.yshop.framework.redis.util.RedissonUtil;
import co.yixiang.yshop.module.product.controller.admin.campaigndetail.vo.CampaignDetailCreateReqVO;
import co.yixiang.yshop.module.product.controller.admin.campaigndetail.vo.CampaignDetailRespVO;
import co.yixiang.yshop.module.product.controller.admin.campaigndetail.vo.CampaignSkuDetailRespVO;
import co.yixiang.yshop.module.product.controller.admin.campaigninfo.param.CampaignJudgmentParam;
import co.yixiang.yshop.module.product.controller.admin.campaigninfo.vo.*;
import co.yixiang.yshop.module.product.convert.campaigndetail.CampaignDetailConvert;
import co.yixiang.yshop.module.product.convert.campaigninfo.CampaignInfoConvert;
import co.yixiang.yshop.module.product.dal.dataobject.campaigndetail.CampaignDetailDO;
import co.yixiang.yshop.module.product.dal.dataobject.campaigninfo.CampaignInfoDO;
import co.yixiang.yshop.module.product.dal.dataobject.storeproduct.StoreProductDO;
import co.yixiang.yshop.module.product.dal.dataobject.storeproductattrvalue.StoreProductAttrValueDO;
import co.yixiang.yshop.module.product.dal.mysql.campaigndetail.CampaignDetailMapper;
import co.yixiang.yshop.module.product.dal.mysql.campaigninfo.CampaignInfoMapper;
import co.yixiang.yshop.module.product.enums.campaign.CampaignStateEnum;
import co.yixiang.yshop.module.product.enums.campaign.CampaignTypeEnum;
import co.yixiang.yshop.module.product.enums.common.PageTypeEnum;
import co.yixiang.yshop.module.product.enums.spu.ProductSpuStatusEnum;
import co.yixiang.yshop.module.product.mq.producer.PayRefundProducer;
import co.yixiang.yshop.module.product.service.storeproduct.StoreProductService;
import co.yixiang.yshop.module.product.service.storeproductattrvalue.StoreProductAttrValueService;
import co.yixiang.yshop.module.product.service.teamworkinfo.TeamworkInfoService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

import static co.yixiang.yshop.framework.common.exception.util.ServiceExceptionUtil.exception;
import static co.yixiang.yshop.module.product.enums.ErrorCodeConstants.*;
import static co.yixiang.yshop.module.product.enums.campaign.CampaignCommonEnum.DEACTIVATE;
import static co.yixiang.yshop.module.product.enums.campaign.CampaignCommonEnum.ENABLE;
import static co.yixiang.yshop.module.product.enums.campaign.CampaignStateEnum.*;
import static co.yixiang.yshop.module.product.enums.campaign.CampaignTypeEnum.TEAMWORK;

/**
 * 活动信息 Service 实现类
 *
 * @author moxiangrong
 */
@Service
@Validated
@Slf4j
public class CampaignInfoServiceImpl implements CampaignInfoService {

    @Resource
    private CampaignInfoMapper campaignInfoMapper;
    @Resource
    private StoreProductAttrValueService productAttrValueService;
    @Resource
    private CampaignDetailMapper campaignDetailMapper;
    @Resource
    private StoreProductService productService;

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private PayRefundProducer payRefundProducer;

    @Resource
    private TeamworkInfoService teamworkInfoService;

    @Resource
    private RedissonUtil redissonUtil;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createCampaignInfo(CampaignInfoCreateReqVO createReqVO) {
        List<CampaignDetailCreateReqVO> details = createReqVO.getDetails();
        // 判断是否选择商品
        if (CollectionUtils.isEmpty(details)) {
            throw exception(CAMPAIGN_NOT_PRODUCT_ERROR);
        }
        Integer type = createReqVO.getType();
        LocalDateTime startTime = createReqVO.getStartTime();
        LocalDateTime endTime = createReqVO.getEndTime();
        // 判断活动是否重复
        List<Long> productIds = checkRepeat(details, null, startTime, endTime);
        // 查询商品数据
        Map<Long, StoreProductDO> productMap = getProductMap(productIds);
        // 获得商品属性值列表
        Map<Long, StoreProductAttrValueDO> productAttrValueDOMap = getProductAttrValueMap(details);
        // 准备扣除库存数据
        List<StoreProductAttrValueDO> updateProductAttrValues = new ArrayList<>();
        Map<Long, StoreProductDO> updateProductMap = new HashMap<>();
        for (CampaignDetailCreateReqVO detail : details) {
            StoreProductAttrValueDO productAttrValueDO = productAttrValueDOMap.get(detail.getSkuId());
            //规格参数检查
            skuParamCheck(productAttrValueDO, detail, type);
            //准备扣减库存
            reduceStockReady(productAttrValueDO, detail, updateProductAttrValues, updateProductMap, productMap);
        }
        // 转换
        CampaignInfoDO campaignInfo = CampaignInfoConvert.INSTANCE.convert(createReqVO);
        // 设置活动状态 和时间
        LocalDateTime time = setStateAndTime(campaignInfo);
        // 插入营销活动数据
        campaignInfoMapper.insert(campaignInfo);
        //先插入主记录，才有id,再插入详情
        List<CampaignDetailDO> campaignDetailDOS = buildCampaignDetailDOS(details, campaignInfo.getId());
        this.insertBatch(campaignDetailDOS);
        if (!ENDED.getValue().equals(campaignInfo.getState())) {
            // 扣除库存
            productAttrValueService.updateBatchById(updateProductAttrValues);
            productService.updateBatchById(updateProductMap.values());
            if (startTime != null && endTime != null) {
                //加入延时队列
                this.addQueue(campaignInfo.getId(), DateUtils.getMoreMillisecondAfter(time));
            }
        }
        // 返回
        return campaignInfo.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateCampaignInfo(CampaignInfoUpdateReqVO updateReqVO) {
        List<CampaignDetailCreateReqVO> details = updateReqVO.getDetails();
        Long id = updateReqVO.getId();
        // 校验存在
        this.validateCampaignInfoExists(id);
        // 判断是否选择商品
        if (CollectionUtils.isEmpty(details)) {
            throw exception(CAMPAIGN_NOT_PRODUCT_ERROR);
        }
        // 回退库存
        this.stackBack(id);
        // 删除活动明细
        campaignDetailMapper.deleteCampaignDetails(id);
        LocalDateTime startTime = updateReqVO.getStartTime();
        LocalDateTime endTime = updateReqVO.getEndTime();
        Integer type = updateReqVO.getType();
        // 判断活动是否重复
        List<Long> productIds = checkRepeat(details, id, startTime, endTime);
        // 查询商品数据
        Map<Long, StoreProductDO> productMap = getProductMap(productIds);
        // 获得商品属性值列表
        Map<Long, StoreProductAttrValueDO> productAttrValueDOMap = getProductAttrValueMap(details);
        // 准备扣除库存数据
        List<StoreProductAttrValueDO> updateProductAttrValues = new ArrayList<>();
        Map<Long, StoreProductDO> updateProductMap = new HashMap<>();
        for (CampaignDetailCreateReqVO detail : details) {
            StoreProductAttrValueDO productAttrValueDO = productAttrValueDOMap.get(detail.getSkuId());
            //规格参数检查
            skuParamCheck(productAttrValueDO, detail, type);
            //准备扣减库存
            reduceStockReady(productAttrValueDO, detail, updateProductAttrValues, updateProductMap, productMap);
        }
        // 转换
        CampaignInfoDO campaignInfo = CampaignInfoConvert.INSTANCE.convert(updateReqVO);
        // 设置活动状态 和时间
        LocalDateTime time = setStateAndTime(campaignInfo);
        List<CampaignDetailDO> campaignDetailDOS = buildCampaignDetailDOS(details, campaignInfo.getId());

        campaignInfoMapper.updateById(campaignInfo);
        this.insertBatch(campaignDetailDOS);
        // 扣除库存
        productAttrValueService.updateBatchById(updateProductAttrValues);
        productService.updateBatchById(updateProductMap.values());
        if (!ENDED.getValue().equals(campaignInfo.getState())) {
            if (startTime != null && endTime != null) {
                this.removeQueue(campaignInfo.getId());
                //加入延时队列
                this.addQueue(campaignInfo.getId(), DateUtils.getMoreMillisecondAfter(time));
            }
        }
    }

    // 判断活动是否重复
    private List<Long> checkRepeat(List<CampaignDetailCreateReqVO> details, Long campaignId, LocalDateTime startTime, LocalDateTime endTime) {
        List<Long> productIds =
                details.stream().map(CampaignDetailCreateReqVO::getProductId).distinct().collect(Collectors.toList());
        CampaignJudgmentParam param = new CampaignJudgmentParam();
        param.setProductIds(productIds);
        param.setCampaignId(campaignId);
        param.setStartTime(startTime);
        param.setEndTime(endTime);
        if (CollectionUtils.isNotEmpty(campaignInfoMapper.checkRepeat(param))) {
            throw exception(CAMPAIGN_REPEAT_ERROR);
        }
        return productIds;
    }

    // 获取商品映射信息
    private Map<Long, StoreProductDO> getProductMap(List<Long> productIds) {
        List<StoreProductDO> products = productService.getStoreProductList(productIds);
        return products.stream().collect(Collectors.toMap(StoreProductDO::getId, Function.identity()));
    }

    // 获得商品属性值列表
    private Map<Long, StoreProductAttrValueDO> getProductAttrValueMap(List<CampaignDetailCreateReqVO> details) {
        List<Long> skuIds = details.stream().map(CampaignDetailCreateReqVO::getSkuId).collect(Collectors.toList());
        List<StoreProductAttrValueDO> productAttrValueDOS =
                productAttrValueService.getStoreProductAttrValueList(skuIds);
        return productAttrValueDOS.stream().collect(Collectors
                .toMap(StoreProductAttrValueDO::getId, Function.identity()));
    }

    /**
     * 规格参数检查
     */
    private void skuParamCheck(StoreProductAttrValueDO productAttrValueDO, CampaignDetailCreateReqVO detail, Integer type) {
        //商品规格原有价格
        BigDecimal skuPrice = productAttrValueDO.getPrice();
        //规格id
        String sku = productAttrValueDO.getSku();

        //设置的兑换积分额
        BigDecimal campaignIntegral = detail.getIntegral();
        //设置的兑换金额
        BigDecimal campaignPrice = detail.getPrice();
        if (ObjectUtil.isNull(productAttrValueDO)) {
            throw exception(STORE_PRODUCT_ATTR_VALUE_NOT_EXISTS);
        }
        // 计算折扣价格
        if (CampaignTypeEnum.DISCOUNT.getValue().equals(type)) {
            detail.setPrice(skuPrice
                    .multiply(detail.getDiscount())
                    .divide(BigDecimal.TEN).setScale(2, RoundingMode.HALF_UP));
            campaignPrice = detail.getPrice();
        }
        // 活动价格不能为0 ，（积分兑换可以）
        if (campaignPrice.compareTo(BigDecimal.ZERO) == 0 && !CampaignTypeEnum.INTEGRAL.getValue().equals(type)) {
            throw exception(CAMPAIGN_PRICE_NOT_ZERO_ERROR, sku);
        }
        // 检测价格
        if (skuPrice.compareTo(campaignPrice) < 0) {
            throw exception(CAMPAIGN_PASS_ORIGINAL_PRICE_ERROR, sku);
        }
        // 检测库存
        if (productAttrValueDO.getStock() < detail.getStock()) {
            throw exception(CAMPAIGN_OUT_OF_STOCK_ERROR, sku);
        }
        //积分活动需要配置兑换积分
        if (CampaignTypeEnum.INTEGRAL.getValue().equals(type) && campaignIntegral == null) {
            throw exception(CAMPAIGN_INTEGRAL_NOT_NULL_ERROR);
        }
    }

    //准备减扣库存
    private void reduceStockReady(StoreProductAttrValueDO productAttrValueDO, CampaignDetailCreateReqVO detail,
                                  List<StoreProductAttrValueDO> updateProductAttrValues, Map<Long, StoreProductDO> updateProductMap,
                                  Map<Long, StoreProductDO> productMap) {
        //商品规格中的剩余库存
        productAttrValueDO.setStock(productAttrValueDO.getStock() - detail.getStock());
        updateProductAttrValues.add(productAttrValueDO);
        // 商品中的剩余库存
        Long productId = productAttrValueDO.getProductId();
        StoreProductDO updateProduct = updateProductMap.get(productId);
        if (ObjectUtil.isNotNull(updateProduct)) {
            updateProduct.setStock(updateProduct.getStock() - detail.getStock());
        } else {
            StoreProductDO product = productMap.get(productId);
            if (ObjectUtil.isNull(product)) throw exception(STORE_PRODUCT_NOT_EXISTS);
            product.setStock(product.getStock() - detail.getStock());
            updateProductMap.put(productId, product);
        }
    }

    //构建活动信息实体
    private LocalDateTime setStateAndTime(CampaignInfoDO campaignInfo) {
        LocalDateTime time = null;
        LocalDateTime startTime = campaignInfo.getStartTime();
        LocalDateTime endTime = campaignInfo.getEndTime();
        // 设置活动状态
        if (ObjectUtil.isNotNull(startTime) && ObjectUtil.isNotNull(endTime)) {
            if (DateUtils.isBelong(startTime, endTime)) {
                // 如果当前时间在这个范围内,状态为进行中
                campaignInfo.setState(IN_PROGRESS.getValue());
                time = endTime;
            } else if (DateUtils.isBefore(startTime)) {
                // 如果活动开始时间大于当前时间,状态为未开始
                campaignInfo.setState(NOT_STARTED.getValue());
                time = startTime;
            } else {
                // 如果不在,状态为已结束
                campaignInfo.setState(ENDED.getValue());
            }
        }
        //   积分兑换，无限制
        if (ObjectUtil.isNull(startTime) && ObjectUtil.isNull(endTime) &&
                CampaignTypeEnum.INTEGRAL.getValue().equals(campaignInfo.getType())) {
            campaignInfo.setState(IN_PROGRESS.getValue());
        }
        // 预热开始时间
        LocalDateTime preheatStartTime = null;
        if (ENABLE.getValue().equals(campaignInfo.getIfEnable()) &&
                NOT_STARTED.getValue().equals(campaignInfo.getState())) {
            preheatStartTime = DateUtils.getMoreMinuteAfter(startTime, -1 * campaignInfo.getEnableTime());
            // 当前时间在预热期间，直接开始预热
            if (DateUtils.isBelong(preheatStartTime, startTime)) {
                campaignInfo.setState(PREHEAT.getValue());
            } else {
                time = preheatStartTime;
            }
        }
        return time;
    }

    //插入营销活动详情
    private void insertBatch(List<CampaignDetailDO> campaignDetailDOS) {
        campaignDetailMapper.insertBatch(campaignDetailDOS);
    }

    //构建活动详情的商品
    public List<CampaignDetailDO> buildCampaignDetailDOS(List<CampaignDetailCreateReqVO> details, Long campaignId) {
        List<CampaignDetailDO> campaignDetailDOS = CampaignDetailConvert.INSTANCE.convertDetails(details);
        campaignDetailDOS.forEach(res -> {
            res.setCampaignId(campaignId);
            res.setTotal(res.getStock());
        });
        return campaignDetailDOS;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCampaignInfo(Long id) {
        // 校验存在
        CampaignInfoDO campaignInfo = this.validateCampaignInfoExists(id);
        // 进行中无法删除活动
        if (IN_PROGRESS.getValue().equals(campaignInfo.getState())) {
            throw exception(CAMPAIGN_IN_PROGRESS_ERROR);
        }
        // 删除
        campaignInfoMapper.deleteById(id);
        // 删除活动明细
        campaignDetailMapper.deleteCampaignDetails(id);
        // 删除等待队列数据
        if (NOT_STARTED.getValue().equals(campaignInfo.getState())) {
            this.removeQueue(id);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void closeCampaignInfo(Long id) {
        // 校验存在
        CampaignInfoDO campaignInfoDO = this.validateCampaignInfoExists(id);
        // 自动取消未成团订单
        if (TEAMWORK.getValue().equals(campaignInfoDO.getType())) {
            // 查询未成团订单
            List<Long> ids = teamworkInfoService.getNotTeamwork(id);
            if (CollectionUtils.isNotEmpty(ids)) {
                // 取消订单并退款
                payRefundProducer.sendPayRefundMessage(ids);
                // 修改拼团失败状态
                teamworkInfoService.updateTeamworkFail(id);
            }
        }
        // 变更活动状态
        CampaignInfoDO update = new CampaignInfoDO();
        update.setId(id);
        update.setState(ENDED.getValue());
        campaignInfoMapper.updateById(update);
        // 回退库存
        this.stackBack(id);
        // 删除自动关闭队列数据
        this.removeQueue(id);
    }

    @Override
    public void startCampaignInfo(Long id) {
        // 校验存在
        CampaignInfoDO campaignInfo = this.validateCampaignInfoExists(id);
        // 变更活动状态
        CampaignInfoDO update = new CampaignInfoDO();
        update.setId(id);
        update.setState(IN_PROGRESS.getValue());
        campaignInfoMapper.updateById(update);
        // 删除自动开始队列数据
        this.removeQueue(id);
        long time = DateUtils.getMoreMillisecondAfter(campaignInfo.getEndTime());
        // 加入延时队列，到时间自动结束
        this.addQueue(id, time);
    }

    private CampaignInfoDO validateCampaignInfoExists(Long id) {
        CampaignInfoDO campaignInfoDO = campaignInfoMapper.selectById(id);
        if (ObjectUtil.isNull(campaignInfoDO)) throw exception(CAMPAIGN_NOT_EXISTS);
        return campaignInfoDO;
    }

    @Override
    public CampaignInfoRespVO getCampaignInfo(Long id) {
        // 校验存在
        CampaignInfoDO campaignInfo = this.validateCampaignInfoExists(id);
        CampaignInfoRespVO result = CampaignInfoConvert.INSTANCE.convert(campaignInfo);

        List<CampaignDetailRespVO> details = new ArrayList<>();
        // 获取商品规格数据
        List<CampaignSkuDetailRespVO> skus = campaignDetailMapper.getCampaignDetails(id);
        if (CollectionUtils.isEmpty(skus)) return result;

        Map<Long, List<CampaignSkuDetailRespVO>> skuMap =
                skus.stream().collect(Collectors.groupingBy(CampaignSkuDetailRespVO::getProductId));

        for (List<CampaignSkuDetailRespVO> list : skuMap.values()) {
            CampaignDetailRespVO detailRespVO = CampaignInfoConvert.INSTANCE.convert(list.get(0));
            detailRespVO.setOriginalStock(list.stream().mapToInt(CampaignSkuDetailRespVO::getOriginalStock).sum());
            List<CampaignSkuDetailRespVO> filterList = list.stream()
                    .filter(item -> item.getStock() != null && item.getTotal() != null)
                    .collect(Collectors.toList());
            detailRespVO.setSkus(filterList);
            details.add(detailRespVO);
        }
        result.setNow(LocalDateTime.now());
        result.setDetails(details);
        return result;
    }

    @Override
    public CampaignInfoRespVO getCampaignInfoByType(Integer type) {
        // 校验存在
        CampaignInfoDO campaignInfo = this.validateCampaignInfoExists2(type);
        CampaignInfoRespVO result = CampaignInfoConvert.INSTANCE.convert(campaignInfo);

        List<CampaignDetailRespVO> details = new ArrayList<>();
        // 获取商品规格数据
        List<CampaignSkuDetailRespVO> skus = campaignDetailMapper.getCampaignDetails(campaignInfo.getId());
        if (CollectionUtils.isEmpty(skus)) return result;

        Map<Long, List<CampaignSkuDetailRespVO>> skuMap =
                skus.stream().collect(Collectors.groupingBy(CampaignSkuDetailRespVO::getProductId));

        for (List<CampaignSkuDetailRespVO> list : skuMap.values()) {
            CampaignDetailRespVO detailRespVO = CampaignInfoConvert.INSTANCE.convert(list.get(0));
            detailRespVO.setOriginalStock(list.stream().mapToInt(CampaignSkuDetailRespVO::getOriginalStock).sum());
            List<CampaignSkuDetailRespVO> filterList = list.stream()
                    .filter(item -> item.getStock() != null && item.getTotal() != null)
                    .collect(Collectors.toList());
            detailRespVO.setSkus(filterList);
            details.add(detailRespVO);
        }
        result.setNow(LocalDateTime.now());
        result.setDetails(details);
        return result;
    }

    private CampaignInfoDO validateCampaignInfoExists2(Integer type) {
        CampaignInfoDO campaignInfoDO = campaignInfoMapper.selectOne(Wrappers.lambdaQuery(CampaignInfoDO.class)
                .eq(CampaignInfoDO::getType,type)
                .eq(CampaignInfoDO::getState, CampaignStateEnum.IN_PROGRESS.getValue())
                .orderByDesc(CampaignInfoDO::getStartTime)
                .last("limit 1")
        );
        if (ObjectUtil.isNull(campaignInfoDO)) throw exception(CAMPAIGN_NOT_EXISTS);
        return campaignInfoDO;
    }


    @Override
    public PageResult<CampaignInfoPageRespVO> getCampaignInfoPage(CampaignInfoPageReqVO pageReqVO) {
        PageResult<CampaignInfoPageRespVO> result =
                CampaignInfoConvert.INSTANCE.convertPage(campaignInfoMapper.selectPage(pageReqVO));
        List<CampaignInfoPageRespVO> list = result.getList();
        if (CollectionUtils.isEmpty(list)) {
            return result;
        }
        // 获取拼团订单数据
        List<Long> campaignIds = list.stream().map(CampaignInfoPageRespVO::getId).collect(Collectors.toList());
        List<CampaignOrderVo> campaignOrderVos = campaignInfoMapper.getCampaignInfoList(campaignIds);
        if (CollectionUtils.isEmpty(list)) {
            return result;
        }
        Map<Long, List<CampaignOrderVo>> orderMap =
                campaignOrderVos.stream().collect(Collectors.groupingBy(CampaignOrderVo::getCampaignId));
        for (CampaignInfoPageRespVO campaignInfoPageRespVO : list) {
            Long id = campaignInfoPageRespVO.getId();
            //积分商城活动中的显示处理
            if (CampaignTypeEnum.INTEGRAL.getValue().equals(pageReqVO.getType())) {
                CampaignInfoRespVO campaignInfo = getCampaignInfo(id);
                CampaignDetailRespVO campaignDetailRespVO = campaignInfo.getDetails().get(0);

                campaignInfoPageRespVO.setProductImage(campaignDetailRespVO.getImage());
                campaignInfoPageRespVO.setProductInfo(campaignDetailRespVO.getStoreName());
                campaignInfoPageRespVO.setIntegral(campaignDetailRespVO.getIntegral());
                campaignInfoPageRespVO.setPrice(campaignDetailRespVO.getPrice());
                campaignInfoPageRespVO.setStock(campaignDetailRespVO.getStock());
            }
            List<CampaignOrderVo> campaignOrders = orderMap.get(id);
            if (CollectionUtils.isEmpty(campaignOrders)) {
                continue;
            }
            // 计算订单数
            campaignInfoPageRespVO.setOrderQuantity(campaignOrders.stream()
                    .map(CampaignOrderVo::getOid).distinct().collect(Collectors.toList()).size());
            // 计算销售额
            campaignInfoPageRespVO.setSalesAmount(campaignOrders.stream()
                    .map(CampaignOrderVo::getPrice).reduce(BigDecimal::add).orElse(BigDecimal.ZERO));
            // 计算销售量
            campaignInfoPageRespVO.setSalesQuantity(campaignOrders.size());
        }
        return result;
    }

    @Override
    public List<CampaignInfoDO> getCampaignInfoList(CampaignInfoExportReqVO exportReqVO) {
        return campaignInfoMapper.selectList(exportReqVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void campaignStateHandle(Long id) {
        // 校验存在
        CampaignInfoDO campaignInfo = this.validateCampaignInfoExists(id);
        Integer state = null;
        // 判断下个状态
        if (IN_PROGRESS.getValue().equals(campaignInfo.getState())) {
            state = ENDED.getValue();
            // 回退库存
            this.stackBack(id);
            // 自动取消未成团订单
            if (TEAMWORK.getValue().equals(campaignInfo.getType())) {
                // 查询未成团订单
                List<Long> ids = teamworkInfoService.getNotTeamwork(id);
                if (CollectionUtils.isNotEmpty(ids)) {
                    // 取消订单并退款
                    payRefundProducer.sendPayRefundMessage(ids);
                    // 修改拼团失败状态
                    teamworkInfoService.updateTeamworkFail(id);
                }
            }
        } else {
            if (NOT_STARTED.getValue().equals(campaignInfo.getState())
                    && ENABLE.getValue().equals(campaignInfo.getIfEnable())) {
                state = PREHEAT.getValue();
            } else if (NOT_STARTED.getValue().equals(campaignInfo.getState())
                    && DEACTIVATE.getValue().equals(campaignInfo.getIfEnable())) {
                state = IN_PROGRESS.getValue();
            } else if (PREHEAT.getValue().equals(campaignInfo.getState())) {
                state = IN_PROGRESS.getValue();
            }
            long time = DateUtils.getMoreMillisecondAfter(IN_PROGRESS.getValue().equals(state) ?
                    campaignInfo.getEndTime() : campaignInfo.getStartTime());
            //加入延时队列
            this.addQueue(id, time);
        }
        // 修改活动状态
        CampaignInfoDO update = new CampaignInfoDO();
        update.setId(id);
        update.setState(state);
        campaignInfoMapper.updateById(update);
    }

    @Override
    public CampaignDataRespVO getCampaignData(Long id) {
        // 校验存在
        CampaignInfoDO campaignInfo = this.validateCampaignInfoExists(id);
        CampaignDataRespVO campaignDataRespVO = new CampaignDataRespVO();
        campaignDataRespVO.setId(id);
        campaignDataRespVO.setName(campaignInfo.getName());
        List<CampaignOrderVo> campaignOrderVos = campaignInfoMapper.getCampaignInfoList(Arrays.asList(id));
        if (CollectionUtils.isEmpty(campaignOrderVos)) return campaignDataRespVO;
        // 成交金额
        campaignDataRespVO.setDealAmount(campaignOrderVos.stream()
                .map(CampaignOrderVo::getPrice).reduce(BigDecimal::add).orElse(BigDecimal.ZERO));
        // 成交单量
        campaignDataRespVO.setDealQuantity(campaignOrderVos.stream()
                .map(CampaignOrderVo::getOid).distinct().collect(Collectors.toList()).size());
        // 成交人数
        campaignDataRespVO.setPeopleNumber(campaignOrderVos.stream()
                .map(CampaignOrderVo::getUid).distinct().collect(Collectors.toList()).size());
        // 成交商品数
        campaignDataRespVO.setProductQuantity(campaignOrderVos.size());
        // 客单价
        campaignDataRespVO.setAveragePrice(campaignDataRespVO.getDealAmount()
                .divide(new BigDecimal(campaignDataRespVO.getDealQuantity())));
        return campaignDataRespVO;
    }

    @Override
    public PageResult<CampaignDataDetailRespVO> getCampaignDataDetail(CampaignDataDetailPageReqVO reqVO) {
        Page<CampaignDataDetailRespVO> page = new Page<>(reqVO.getPageNo(), reqVO.getPageSize());
        List<CampaignDataDetailRespVO> list = campaignDetailMapper.getCampaignDataDetail(page, reqVO);
        if (CollectionUtils.isEmpty(list)) return new PageResult<>();
        // 获取订单数据
        List<CampaignOrderVo> campaignOrderVos =
                campaignInfoMapper.getCampaignInfoList(Arrays.asList(reqVO.getId()));
        if (CollectionUtils.isEmpty(campaignOrderVos)) return new PageResult<>(list, page.getTotal());
        Map<String, List<CampaignOrderVo>> skuOrderMap =
                campaignOrderVos.stream().collect(Collectors.groupingBy(CampaignOrderVo::getUnique));
        for (CampaignDataDetailRespVO respVO : list) {
            List<CampaignOrderVo> skuOrders = skuOrderMap.get(respVO.getUnique());
            if (CollectionUtils.isEmpty(skuOrders)) continue;
            // 成交金额
            respVO.setDealAmount(skuOrders.stream()
                    .map(CampaignOrderVo::getPrice).reduce(BigDecimal::add).orElse(BigDecimal.ZERO));
            // 成交单量
            respVO.setDealQuantity(skuOrders.stream()
                    .map(CampaignOrderVo::getOid).distinct().collect(Collectors.toList()).size());
            // 成交人数
            respVO.setPeopleNumber(skuOrders.stream()
                    .map(CampaignOrderVo::getUid).distinct().collect(Collectors.toList()).size());
            // 成交商品数
            respVO.setProductQuantity(skuOrders.size());
            // 客单价
            respVO.setAveragePrice(respVO.getDealAmount().divide(new BigDecimal(respVO.getDealQuantity())));
        }
        return new PageResult<>(list, page.getTotal());
    }


    @Override
    public PageResult<CanvasCampaignPageRespVO> getCanvasCampaignPage(CanvasCampaignPageReqVO pageReqVO) {
        if (PageTypeEnum.NOT_PAGE.getValue().equals(pageReqVO.getIsPage())) pageReqVO.setPageSize(Integer.MAX_VALUE);
        return CampaignInfoConvert.INSTANCE.convertCanvasPage(campaignInfoMapper.getCanvasCampaignPage(pageReqVO));
    }


    /**
     * 回退库存
     *
     * @param campaignId 营销活动id
     */
    private void stackBack(Long campaignId) {
        // 查询活动的商品明细数据
        List<CampaignDetailDO> details =
                campaignDetailMapper.selectList(new LambdaQueryWrapper<CampaignDetailDO>()
                        .eq(CampaignDetailDO::getCampaignId, campaignId));
        if (CollectionUtils.isEmpty(details)) return;
        List<Long> productIds =
                details.stream().map(CampaignDetailDO::getProductId).distinct().collect(Collectors.toList());
        // 查询商品数据
        List<StoreProductDO> products = productService.getStoreProductList(productIds);
        if (CollectionUtils.isEmpty(products)) return;
        // 过滤未上架商品
        products = products.stream().filter(res -> ProductSpuStatusEnum.ENABLE.getStatus().equals(res.getIsShow()))
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(products)) return;
        Map<Long, StoreProductDO> productMap =
                products.stream().collect(Collectors.toMap(StoreProductDO::getId, Function.identity()));
        List<Long> skuIds = details.stream().map(CampaignDetailDO::getSkuId).collect(Collectors.toList());
        List<StoreProductAttrValueDO> skus = productAttrValueService.getStoreProductAttrValueList(skuIds);
        Map<Long, StoreProductAttrValueDO> skuMap =
                skus.stream().collect(Collectors.toMap(StoreProductAttrValueDO::getId, Function.identity()));
        // 返还库存
        List<StoreProductAttrValueDO> updateSkus = new ArrayList<>();
        Map<Long, StoreProductDO> updateProductMap = new HashMap<>();
        for (CampaignDetailDO detail : details) {
            StoreProductAttrValueDO sku = skuMap.get(detail.getSkuId());
            if (ObjectUtil.isNull(sku)) continue;
            sku.setStock(sku.getStock() + detail.getStock());
            updateSkus.add(sku);
            StoreProductDO updateProduct = updateProductMap.get(detail.getProductId());
            if (ObjectUtil.isNull(updateProduct)) {
                StoreProductDO product = productMap.get(detail.getProductId());
                if (ObjectUtil.isNull(product)) continue;
                product.setStock(product.getStock() + detail.getStock());
                updateProductMap.put(detail.getProductId(), product);
            } else {
                updateProduct.setStock(updateProduct.getStock() + detail.getStock());
            }
        }
        // 回退库存
        productAttrValueService.updateBatchById(updateSkus);
        productService.updateBatchById(updateProductMap.values());
    }

    /**
     * 加入延时队列
     *
     * @param id
     * @param time
     */
    private void addQueue(Long id, long time) {
        log.info("添加延时队列 ，营销活动id：{}, 延时时间：{}", id, time);
        redissonUtil.delayedOfferThrow(ShopConstants.CAMPAIGN_CHANGE, id, time, TimeUnit.MILLISECONDS, CAMPAIGN_ADD_QUEUE_ERROR);
    }

    /**
     * 从延时队列中移除
     *
     * @param id
     */
    private void removeQueue(Long id) {
        redissonUtil.delayedRemoveThrow(ShopConstants.CAMPAIGN_CHANGE, id, CAMPAIGN_REMOVE_QUEUE_ERROR);
        log.info("移除延时队列成功 ，营销活动id：{}", id);
    }
}
